﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Dapper;

namespace ComTools
{
    public partial class frmMotor : Form
    {
        public frmMotor()
        {
            InitializeComponent();
        }

        private void frmLocation_Load(object sender, EventArgs e)
        {
            for(int i = 1; i <= 32;i++)
            {
                Control[] c = panel2.Controls.Find("checkBox" + i.ToString(), false);
                if (c.Length > 0 && c[0] is CheckBox)
                {
                    CheckBox xx = c[0] as CheckBox;
                    DicChecks.Add(i, xx);
                }
            }
        }

        Dictionary<int, CheckBox> DicChecks = new Dictionary<int, CheckBox>();

        //定义回调:解决跨线程访问问题
        private delegate void SetTextValueCallBack(string strValue);
        //定义接收客户端发送消息的回调
        private delegate void ReceiveMsgCallBack(string strReceive);

        //定义回调：给ComboBox控件添加元素
        private delegate void SetCmbCallBack(string strItem);

        //定义发送文件的回调
        private delegate void SendFileCallBack(byte[] bf);

        //用于通信的Socket
        Socket socketSend;
        //用于监听的SOCKET
        Socket socketWatch;

        //将远程连接的客户端的IP地址和Socket存入集合中
        Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();
        private ReceiveMsgCallBack receiveCallBack;

        //创建监听连接的线程
        Thread AcceptSocketThread;
        //接收客户端发送消息的线程
        Thread threadReceive;

        private void btn_Start_Click(object sender, EventArgs e)
        {
            try
            {
                //当点击开始监听的时候 在服务器端创建一个负责监听IP地址和端口号的Socket
                socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //获取ip地址
                IPAddress ip = null;
                if (this.txt_IP.Text.Trim() == "0.0.0.0")
                {
                    ip = IPAddress.Any;
                }
                else
                {
                    ip = IPAddress.Parse(this.txt_IP.Text.Trim());
                }
                //创建端口号
                IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(this.txt_Port.Text.Trim()));
                //绑定IP地址和端口号
                socketWatch.Bind(point);
                ShowLog("监听成功");
                //开始监听:设置最大可以同时连接多少个请求
                socketWatch.Listen(10);

                //实例化回调
                receiveCallBack = new ReceiveMsgCallBack(ReceiveMsg);

                //创建线程开始监听
                AcceptSocketThread = new Thread(new ParameterizedThreadStart(StartListen));
                AcceptSocketThread.IsBackground = true;
                AcceptSocketThread.Start(socketWatch);
            }
            catch (Exception exc)
            {
                ShowLog(exc.Message);
            }
        }


        private void InneterAccepct(IAsyncResult iasync)
        {
            try
            {
                Socket temp = iasync.AsyncState as Socket;
                //等待客户端的连接，并且创建一个用于通信的Socket
                socketSend = temp.EndAccept(iasync);
                temp.BeginAccept(new AsyncCallback(InneterAccepct), temp);
                //获取远程主机的ip地址和端口号
                string strIp = socketSend.RemoteEndPoint.ToString();
                dicSocket.Add(strIp, socketSend);
                string strMsg = "远程主机：" + socketSend.RemoteEndPoint + "连接成功";
                //使用回调
                ShowLog(strMsg);

                //定义接收客户端消息的线程
                Thread threadReceive = new Thread(new ParameterizedThreadStart(Receive));
                threadReceive.IsBackground = true;
                threadReceive.Start(socketSend);
            }
            catch (Exception exc)
            {
                ShowLog(exc.Message);
            }
        }

        private void ReceiveMsg(string strMsg)
        {
            ShowLog(strMsg);
        }

        /// <summary>
        /// 回调委托需要执行的方法
        /// </summary>
        /// <param name="strValue"></param>
        private void SetTextValue(string strValue)
        {
            this.txt_Log.AppendText(strValue + Environment.NewLine);
        }

        Action<string> setCallBack = null;
        private void ShowLog(string strValue)
        {
            if (setCallBack == null)
            {
                setCallBack = new Action<string>(SetTextValue);
            }
            txt_Log.Invoke(setCallBack, strValue);
        }

        /// <summary>
        /// 等待客户端的连接，并且创建与之通信用的Socket
        /// </summary>
        /// <param name="obj"></param>
        private void StartListen(object obj)
        {
            Socket socketWatch = obj as Socket;
            socketWatch.BeginAccept(new AsyncCallback(InneterAccepct), socketWatch);

        }

        private void InnerReceive(IAsyncResult iasync)
        {
            try
            {
                Dictionary<string, object> dic = iasync.AsyncState as Dictionary<string, object>;
                Socket temp = dic["Socket"] as Socket;
                byte[] buffer = dic["Buffer"] as byte[];
                //
                //实际接收到的有效字节数
                int count = temp.EndReceive(iasync);
                if (count > 0)
                {
                    byte[] sendData = GetBytesByType(buffer.Take(count).ToArray());
                    SendLogic(temp, sendData);

                    string str = BitConverter.ToString(buffer, 0, count);

                    string strReceiveMsg = "接收：" + socketSend.RemoteEndPoint + "发送的消息:" + str;
                    ShowLog(strReceiveMsg);
                }

                buffer = new byte[2048];
                Dictionary<string, object> dic2 = new Dictionary<string, object>();
                dic2.Add("Socket", temp);
                dic2.Add("Buffer", buffer);
                temp.BeginReceive(buffer, 0, 2048, SocketFlags.None, InnerReceive, dic2);
            }
            catch (Exception exc)
            {
                ShowLog(exc.Message);
            }
        }

        string[] colors = new string[] { "红", "黄", "绿", "蓝" };

        private byte[] GetBytesByType(byte[] buffer)
        {
            byte[] sendData = new byte[2];

            //01 04 00 00 00 20 F1 D2
            if (buffer.Length == 8 && buffer[1] == 0x04 && buffer[2] == 0 && buffer[3] == 0
                && buffer[4] == 0 && buffer[5] == 0x20)
            {
                byte[] temp = new byte[]
                {
                    buffer[0], buffer[1], 0x40,
                    0,0,0,0,0,0,0,0,0,0,
                    0,0,0,0,0,0,0,0,0,0,
                    0,0,0,0,0,0,0,0,0,0,
                    0,0,0,0,0,0,0,0,0,0,
                    0,0,0,0,0,0,0,0,0,0,
                    0,0,0,0,0,0,0,0,0,0,
                    0,0,0,0
                 };

                byte[] bits = ComputeReturn();
                Array.Copy(bits, 0, temp, 3, bits.Length);

                byte[] crc = CRC.CRC16(temp);
                
                sendData = new byte[69];
                Array.Copy(temp, sendData, temp.Length);
                if (BitConverter.IsLittleEndian)
                {
                    crc = crc.Reverse().ToArray();
                }
                Array.Copy(crc, 0, sendData, 67, crc.Length);
            }

            return sendData;
        }

        private void SendLogic(Socket socket, byte[] buffer)
        {
            try
            {
                SocketError socketError;
                socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, out socketError,
                    new AsyncCallback((iasync) =>
                    {
                        Socket socket1 = iasync.AsyncState as Socket;
                        socket1.EndSend(iasync);
                    }), socket);
            }
            catch (Exception exc)
            {
                ShowLog(exc.Message);
            }
        }

        /// <summary>
        /// 服务器端不停的接收客户端发送的消息
        /// </summary>
        /// <param name="obj"></param>
        private void Receive(object obj)
        {
            try
            {
                Socket socketSend = obj as Socket;
                //客户端连接成功后，服务器接收客户端发送的消息
                byte[] buffer = new byte[2048];
                Dictionary<string, object> dic = new Dictionary<string, object>();
                dic.Add("Socket", socketSend);
                dic.Add("Buffer", buffer);
                socketSend.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(InnerReceive), dic);
            }
            catch (Exception exc)
            {
                ShowLog(exc.Message);
            }
        }

        frmSetComPort setComPort = new frmSetComPort();

        private void btn3SetComm_Click(object sender, EventArgs e)
        {
            if (setComPort.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            txt3ComPort.Text = setComPort.PortName;
            txt3BaudRate.Text = setComPort.BaudRate.ToString();
            txt3DataBits.Text = setComPort.DataBits.ToString();
            txt3StopBits.Text = setComPort.StopBits.ToString();
            txt3Parity.Text = setComPort.Parity.ToString();
            //
            serialPort1.PortName = setComPort.PortName;
            serialPort1.BaudRate = setComPort.BaudRate;
            serialPort1.DataBits = setComPort.DataBits;
            serialPort1.StopBits = setComPort.StopBits;
            serialPort1.Parity = setComPort.Parity;
        }

        private void btn3Open_Click(object sender, EventArgs e)
        {
            serialPort1.DataReceived += SerialPort1_DataReceived;
            serialPort1.Open();
            SP3State(serialPort1.IsOpen);
        }

        private void SerialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            SerialPort sp = sender as SerialPort;
            int sleeptime = GetSleepTime();
            System.Threading.Thread.Sleep(sleeptime);
            int length = sp.BytesToRead;
            //
            byte[] data = new byte[length];
            sp.Read(data, 0, length);
            Output3("收到数据 " + BitConverter.ToString(data));
            //
            byte[] r = DealData(data);
            if (r.Length > 0)
            {
                sp.Write(r, 0, r.Length);
                Output3Line("返回数据 " + BitConverter.ToString(r));
            }
            else
            {
                Output3Line(" -- 处理结束");
            }
        }

        Func<int> handlerSleepTime = null;
        private int GetSleepTime()
        {
            if (handlerSleepTime == null)
            {
                handlerSleepTime = new Func<int>(() =>
                {
                    int t;
                    if (!int.TryParse(txt3SleepTime.Text.Trim(), out t))
                    {
                        t = 0;
                    }
                    return t;
                });
            }
            object obj = txt3SleepTime.Invoke(handlerSleepTime);
            return Convert.ToInt32(obj);
        }

        private void btn3close_Click(object sender, EventArgs e)
        {
            serialPort1.DataReceived -= SerialPort1_DataReceived;
            serialPort1.Close();
            SP3State(serialPort1.IsOpen);
        }

        Func<byte[], byte[]> HandlerDealData = null;

        Random random = new Random(new Random().Next(0, 999));

        private byte[] DealData(byte[] data)
        {
            int downMin = 4000;
            int downMax = 4020;
            if (HandlerDealData == null)
            {
                HandlerDealData = new Func<byte[], byte[]>((bytes) =>
                {
                    byte[] result = new byte[0];
                    if (bytes.Length == 0)
                        return result;
                    //
                    //01 03 00 0C 00 04 84 0A
                    //E820输入通道1和2
                    if (bytes[1] == 0x03 && bytes[2] == 0x00 && bytes[3] == 0x0C && bytes[4] == 0x00 && bytes[5] == 0x04)
                    {
                        byte len = (byte)(bytes[5] * 2);
                        byte[] temp = new byte[3 + len];
                        result = new byte[5 + len];
                        //
                        temp[0] = bytes[0];
                        temp[1] = bytes[1];
                        temp[2] = len;
                        //
                        int f1 = GetChecked(checkBox1) ? GetNUDValue(tab3Rule5AI1From) : downMin;
                        int t1 = GetChecked(checkBox1) ? GetNUDValue(tab3Rule5AI1To) : downMax;
                        short x1 = (short)random.Next(f1, t1);
                        byte[] a1 = BitConverter.GetBytes(x1);
                        Array.Copy(a1, 0, temp, 3, a1.Length);
                        //
                        int f2 = GetChecked(checkBox2) ? GetNUDValue(tab3Rule5AI2From) : downMin;
                        int t2 = GetChecked(checkBox2) ? GetNUDValue(tab3Rule5AI2To) : downMax;
                        short x2 = (short)random.Next(f2, t2);
                        byte[] a2 = BitConverter.GetBytes(x2);
                        Array.Copy(a2, 0, temp, 5, a2.Length);
                        //
                        int f3 = GetChecked(checkBox3) ? GetNUDValue(tab3Rule5AI3From) : downMin;
                        int t3 = GetChecked(checkBox3) ? GetNUDValue(tab3Rule5AI3To) : downMax;
                        short x3 = (short)random.Next(f3, t3);
                        byte[] a3 = BitConverter.GetBytes(x3);
                        Array.Copy(a3, 0, temp, 7, a3.Length);
                        //
                        int f4 = GetChecked(checkBox4) ? GetNUDValue(tab3Rule5AI4From) : downMin;
                        int t4 = GetChecked(checkBox4) ? GetNUDValue(tab3Rule5AI4To) : downMax;
                        short x4 = (short)random.Next(f2, t2);
                        byte[] a4 = BitConverter.GetBytes(x4);
                        Array.Copy(a4, 0, temp, 9, a4.Length);
                        //
                        byte[] crc2 = CRC.CRC16(temp, true);
                        Array.Copy(temp, result, temp.Length);
                        Array.Copy(crc2, 0, result, temp.Length, crc2.Length);
                    }
                    else
                    {
                        Output3Line("收到数据不符合所选规则");
                    }

                    return result;
                });
            }
            byte[] rr = HandlerDealData.Invoke(data);
            return rr;
        }

        Func<NumericUpDown, decimal> handlerNumericUpDown = null;
        private int GetNUDValue(NumericUpDown nud)
        {
            if (handlerNumericUpDown == null)
            {
                handlerNumericUpDown = new Func<NumericUpDown, decimal>((xnud) => {
                    return xnud.Value;
                });
            }
            object obj = this.Invoke(handlerNumericUpDown, nud);
            return Convert.ToInt32(obj);
        }

        private byte[] ComputeReturn()
        {
            byte[] Bits = new byte[64];
            byte zero = 0x00;
            byte one = 0x01;
            for (int i = 1; i <= 32; i++)
            {
                Bits[2 * (i - 1) + 1] = GetChecked(DicChecks[i]) ? zero : one;
            }
            return Bits;
        }

        private void SP3State(bool open)
        {
            btn3Open.Enabled = !open;
            btn3close.Enabled = open;
            btn3SetComm.Enabled = !open;
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            txt_Log.Clear();
        }

        Func<CheckBox, bool> handlerGetChecked;

        private bool GetChecked(CheckBox cbx)
        {
            if (handlerGetChecked == null)
            {
                handlerGetChecked = new Func<CheckBox, bool>((checkBox) => { return checkBox.Checked; });
            }
            object obj = cbx.Invoke(handlerGetChecked, cbx);
            return Convert.ToBoolean(obj);
        }

        #region text.output

        Action<string> handler3Output = null;

        private void Output3(string msg)
        {
            if (handler3Output == null)
            {
                handler3Output = new Action<string>((txt) =>
                {
                    txt_Log.AppendText(txt);
                });
            }
            txt_Log.BeginInvoke(handler3Output, msg);
        }

        private void Output3Line(string msg)
        {
            Output3(msg + Environment.NewLine);
        }

        #endregion

        private void cbxAllOffOn_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox cbx = sender as CheckBox;
            CheckAll(cbx.Checked);            
        }

        private void CheckAll(bool torf)
        {
            for (int i = 1; i <= 32; i++)
            {
                CheckBox xx = DicChecks[i];
                xx.Checked = torf;
            }
        }
    }
}